package com.library.ezd.handle;

import com.fazecast.jSerialComm.SerialPort;
import com.payne.reader.base.Consumer;
import com.payne.reader.communication.ConnectHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.atomic.AtomicBoolean;

public class JSerialPortHandle implements ConnectHandle {
    private SerialPort mSerialPort;
    private final String mPort;
    private final int mBaud;

    private ReceiveThread mReceiveThread;
    private volatile Consumer<byte[]> mConsumer;
    private volatile OutputStream mOutputStream;
    private volatile InputStream mInputStream;
    private final AtomicBoolean mIsConnected;

    private Logger log = LoggerFactory.getLogger(JSerialPortHandle.class);

//    private SerialPortDataListener mL = new SerialPortDataListener() {
//        @Override
//        public int getListeningEvents() {
//            return SerialPort.LISTENING_EVENT_DATA_RECEIVED;
//        }
//
//        @Override
//        public void serialEvent(SerialPortEvent serialPortEvent) {
//            System.out.println("getEventType:" + serialPortEvent.getEventType());
//            if (mConsumer == null) {
//                return;
//            }
//            byte[] bytes = serialPortEvent.getReceivedData();
//            System.out.println("recv: " + bytes.length);
//            try {
//                mConsumer.accept(bytes);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
//    };

    public JSerialPortHandle(String port, int baud) {
        mPort = port;
        mBaud = baud;
        mIsConnected = new AtomicBoolean(false);
    }

    @Override
    public boolean onConnect() {
        synchronized (this) {
            onDisconnect();
            try {
                mSerialPort = SerialPort.getCommPort(mPort);
                boolean openPort = mSerialPort.openPort();
                if (!openPort) {
                    return false;
                }
                mSerialPort.setComPortParameters(mBaud, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
                // mSerialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 1000, 1000);
                try {
                    //打开串口后要休眠一段时间才能接收到输入流
                    Thread.sleep(1000);
                } catch (Exception ignored) {}
                // mSerialPort.addDataListener(mL);
                mOutputStream = mSerialPort.getOutputStream();
                mInputStream = mSerialPort.getInputStream();

                mReceiveThread = new ReceiveThread();
                mReceiveThread.start();

                mIsConnected.set(true);
            } catch (Exception e) {
                mIsConnected.set(false);
                System.err.println("can't connect because: " + e.getMessage());
            }
            return mIsConnected.get();
        }
    }

    @Override
    public boolean isConnected() {
        return mIsConnected.get();
    }

    @Override
    public void onSend(byte[] bytes) throws Exception {
        synchronized (this) {
            if (mOutputStream != null) {
                mOutputStream.write(bytes);
            }
        }
    }

    @Override
    public void onReceive(Consumer<byte[]> consumer) {
        mConsumer = consumer;
    }

    @Override
    public void onDisconnect() {
        synchronized (this) {
            mIsConnected.set(false);

            if (mOutputStream != null) {
                try {
                    mOutputStream.close();
                } catch (IOException ignored) {
                }
                mOutputStream = null;
            }
            if (mInputStream != null) {
                try {
                    mInputStream.close();
                } catch (IOException ignored) {
                }
                mInputStream = null;
            }
            if (mSerialPort != null) {
                mSerialPort.closePort();
                mSerialPort = null;
            }
            mReceiveThread = null;
        }
    }

    @Override
    public void release() {
        onDisconnect();
    }

    @Deprecated
    private class ReceiveThread extends Thread {

        @Override
        public void run() {
            byte[] dataBuffer = new byte[1024];

            while (mIsConnected.get()) {

                if (mInputStream == null) {
                    return;
                }
                try {
                    // 可用的
                    int available = mInputStream.available();
                    if (available <= 0) {
                        try {
                            Thread.sleep(100L);
                        } catch (Throwable ignored) {
                        }
                    }
                    int readLen = mInputStream.read(dataBuffer, 0, available);
                    byte[] receiveBytes = new byte[readLen];
                    System.arraycopy(dataBuffer, 0, receiveBytes, 0, readLen);

                    if (mConsumer != null) {
                        mConsumer.accept(receiveBytes);
                    }
                } catch (Exception e) {
//                    System.err.println(LLLog.getStackTrace(3) + "read com error: " + e);
                    return;
                }
            }
        }
    }

}
